package com.benshou.bcss.common.db;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.benshou.bcss.common.j17common.CollectorX;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.time.ZonedDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * MetaObjectHandler: 全局处理器
 * <p>
 *     因为 MetaObjectHandler 的 Bean 必须是单例，故声明为全局。
 *     如果需要特殊处理，可以分流处理。{@link MultitonMetaObjectHandler}
 * </p>
 *
 * @author <a href="mailto:liuzhenbang@benshou.com">Liu Zhenbang</a>
 * @see MultitonMetaObjectHandler
 * @see ClassMetaObjectHandler
 */
@Component
@RequiredArgsConstructor
public class GlobalMetaObjectHandler implements MetaObjectHandler {

    /**
     * Id 生成器
     */
    private final IdentifierGenerator idGenerator;

    /**
     * 列表：分流 MetaObjectHandler
     */
    private final List<ClassMetaObjectHandler> classMetaObjectHandlers;

    /**
     * 映射：分流 MetaObjectHandler（基于 Class ）
     * <p>
     *     基于性能影响，仅提供精确匹配，不支持继承关系。
     * </p>
     */
    private Map<Class<?>, ClassMetaObjectHandler> classMetaObjectHandlerMap;

    @PostConstruct
    private void postConstruct() {
        this.classMetaObjectHandlerMap = this.classMetaObjectHandlers.stream()
                .collect(CollectorX.toUniqueKeyMap(ClassMetaObjectHandler::resolveOriginalObjectClass));
    }

    @Override
    public void insertFill(MetaObject metaObject) {
        var originalObject = metaObject.getOriginalObject();
        if (originalObject instanceof BaseEntity) {
            // 填充租户编号
            setFieldValByName(
                    BaseEntity.NAME_TENANT_ID,
                    BaseEntity.getCurrentTenantId(),
                    metaObject);
            // 填充当前用户编号
            var currentUserNo = BaseEntity.getCurrentUserNo();
            setFieldValByName(BaseEntity.NAME_CREATED_BY, currentUserNo, metaObject);
            setFieldValByName(BaseEntity.NAME_UPDATED_BY, currentUserNo, metaObject);

            // 填充当前时间
            var currentTime = ZonedDateTime.now();
            strictInsertFill(metaObject, BaseEntity.NAME_CREATED_TIME, ZonedDateTime.class, currentTime);
            strictInsertFill(metaObject, BaseEntity.NAME_UPDATED_TIME, ZonedDateTime.class, currentTime);

            // 填充默认值
            strictInsertFill(metaObject, BaseEntity.NAME_VERSION, Integer.class, BaseEntity.VERSION_INITIAL);
            strictInsertFill(metaObject, BaseEntity.NAME_IS_DELETED, Boolean.class, false);
        }

        // 填充业务编号
        var originalObjectCls = originalObject.getClass();
        ReflectionUtils.doWithFields(
                originalObjectCls,
                field -> {
                    // 纯数字，类型为 long
                    Optional.ofNullable(field.getAnnotation(BusinessNoLong.class))
                            .ifPresent(annotation ->
                                    strictInsertFill(metaObject, field.getName(), Long.class, generateBusinessNo()));
                    // 字符串，更自由，可加前缀，类型为 string
                    Optional.ofNullable(field.getAnnotation(BusinessNoString.class))
                            .ifPresent(annotation -> {
                                strictInsertFill(
                                        metaObject,
                                        field.getName(),
                                        String.class,
                                        annotation.prefix() + generateBusinessNo());});});

        // 分流：特定类型的自动填充
        Optional.ofNullable(this.classMetaObjectHandlerMap.get(originalObjectCls))
                .ifPresent(handler -> handler.insertFill(this, metaObject));
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        var originalObject = metaObject.getOriginalObject();
        if (originalObject instanceof BaseEntity) {
            // 填充更新信息
            setFieldValByName(BaseEntity.NAME_UPDATED_BY, BaseEntity.getCurrentUserNo(), metaObject);
            setFieldValByName(BaseEntity.NAME_UPDATED_TIME, ZonedDateTime.now(), metaObject);
        }

        // 分流：特定类型的自动填充
        Optional.ofNullable(this.classMetaObjectHandlerMap.get(originalObject.getClass()))
                .ifPresent(handler -> handler.updateFill(this, metaObject));
    }

    /**
     * @return 业务编号（ long ）
     */
    private long generateBusinessNo() {
        return this.idGenerator.nextId(null).longValue();
    }
}
